#include <crt_util.h>

void* heap_malloc(size_t size)
{
    void* ptr = NULL;
#if (TARGET_OS == OS_WIN)

    HANDLE heap = GetProcessHeap();
    HeapLock(heap);

    ptr = HeapAlloc(heap, 0, size);

    HeapUnlock(heap);

#elif (TARGET_OS == OS_POSIX)
    ptr = malloc(size);
#elif (TARGET_OS == OS_MACH)
    ptr = malloc(size);
#elif (TARGET_OS == OS_UNIX)
    ptr = malloc(size);
#endif

    return ptr;
}
void heap_free(void* ptr)
{
    if (ptr != NULL) {
#if (TARGET_OS == OS_WIN)

        HANDLE heap = GetProcessHeap();
        HeapLock(heap);

        HeapFree(heap, 0, ptr);

        HeapUnlock(heap);

#elif (TARGET_OS == OS_POSIX)
        free(ptr);
#elif (TARGET_OS == OS_MACH)
        free(ptr);
#elif (TARGET_OS == OS_UNIX)
        free(ptr);
#endif
        ptr = NULL;
    }
}
void* heap_calloc(size_t count, size_t size)
{
    void* ptr = NULL;
#if (TARGET_OS == OS_WIN)

    HANDLE heap = GetProcessHeap();
    HeapLock(heap);
    ptr = HeapAlloc(heap, HEAP_ZERO_MEMORY, count * size);
    HeapUnlock(heap);

#elif (TARGET_OS == OS_POSIX)
    ptr = calloc(count, size);
#elif (TARGET_OS == OS_MACH)
    ptr = calloc(count, size);
#elif (TARGET_OS == OS_UNIX)
    ptr = calloc(count, size);
#endif
    return ptr;
}
void* heap_realloc(void* mem_address, size_t size)
{
    void* ptr = NULL;
#if (TARGET_OS == OS_WIN)
    HANDLE heap = GetProcessHeap();
    HeapLock(heap);
    ptr = HeapReAlloc(heap, 0, mem_address, size);
    HeapUnlock(heap);
#elif (TARGET_OS == OS_POSIX)
    ptr = realloc(mem_address, size);
#elif (TARGET_OS == OS_MACH)
    ptr = realloc(mem_address, size);
#elif (TARGET_OS == OS_UNIX)
    ptr = realloc(mem_address, size);
#endif
    return ptr;
}

char* heap_strdup(const char* str)
{
    char* sdup;
    size_t len = s_strlen(str) + 1;

    sdup = (char*)heap_malloc(len);
    if (sdup == NULL)
        return NULL;
    s_memcpy(sdup, str, len);

    return sdup;
}
void* s_memset(void* dst, int val, size_t count)
{
    void* start = dst;

    while (count--) {
        *(char*)dst = (char)val;
        dst = (char*)dst + 1;
    }
    return (start);
}

wchar_t* s_wmemset(wchar_t* dst, wchar_t c, size_t count)
{
    wchar_t* _Su = dst;
    for (; 0 < count; ++_Su, --count) {
        *_Su = c;
    }
    return (dst);
}

void* s_memchr(const void* s, int c, size_t n)
{
    if (n > 0) {
        const unsigned char* p = s;
        const unsigned char* q = s;

        p += n - 1;

        while (p >= q) {
            if (*p == (unsigned char)c)
                return (void*)p;
            p--;
        }
    }
    return NULL;
}

wchar_t* s_wmemchr(const wchar_t* s, wchar_t c, size_t n)
{
    for (; 0 < n; ++s, --n)
        if (*s == c)
            return (wchar_t*)(s);
    return (0);
}

int s_memicmp(const void* first, const void* last, size_t count)
{
    int f = 0;
    int l = 0;
    while (count--) {
        if ((*(unsigned char*)first == *(unsigned char*)last)
            || ((f = _crt_tolower(*(unsigned char*)first)) == (l = _crt_tolower(*(unsigned char*)last)))) {
            first = (char*)first + 1;
            last = (char*)last + 1;
        } else
            break;
    }
    return (f - l);
}
int s_wmemcmp(const wchar_t* first, const wchar_t* last, size_t count)
{
    for (; 0 < count; ++first, ++last, --count)
        if (*first != *last)
            return (*first < *last ? -1 : +1);
    return (0);
}

void* s_memcpy(void* dest, const void* src, size_t count)
{
    void* ret = dest;
    while (count--) {
        *(char*)dest = *(char*)src;
        dest = (char*)dest + 1;
        src = (char*)src + 1;
    }
    return (ret);
}
wchar_t* s_wmemcpy(wchar_t* dest, const wchar_t* src, size_t count)
{
    return (wchar_t*)s_memcpy(dest, src, count * sizeof(wchar_t));
}
